package com.foreverwin.jzymes.report.cpk.service.impl;


import com.foreverwin.jzymes.common.constant.Constants;
import com.foreverwin.jzymes.common.service.*;
import com.foreverwin.jzymes.framework.exception.BusinessException;
import com.foreverwin.jzymes.framework.util.I18nUtil;
import com.foreverwin.jzymes.report.cpk.mapper.CPKReportMapper;
import com.foreverwin.jzymes.report.cpk.service.ICPKReportService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class CPKReportServiceImpl implements ICPKReportService {
    @Autowired
    CPKReportMapper cpkReportMapper;
    @Autowired
    IDCGroupAdviceService dcGroupAdviceService;
    @Autowired
    IFieldGroupAdviceService fieldGroupAdviceService;
    @Autowired
    IItemGroupAdviceService itemGroupAdviceService;
    @Autowired
    IResourceAdviceService resourceAdviceService;


    /**
     * CPK报表
     * @param jsonMap
     * @return
     */
    @Override
    public List<Map<String, Object>> findCPKByReport(Map<String, Object> jsonMap) {
        String site = (String) jsonMap.get("site");
        String cncType = (String) jsonMap.get("cncType");
        String resrce = (String) jsonMap.get("resrce");
        String fail = (String) jsonMap.get("fail");

        String machineType = itemGroupAdviceService.findItemGroupBySite( site );
        /**检查夹位*/
        fieldGroupAdviceService.existFieldGroup( site , Constants.FIELD_GROUP_CncType , cncType );
        /**检查设备*/
        resourceAdviceService.existResource(site,resrce);
        cncType = cncType.substring(2,6);
        String dcBo =machineType + "_"+cncType;
        String dcGroup = dcGroupAdviceService.findDCGroupBo( site , dcBo );

        Date startDate = null;
        Date endDate = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        Assert.isTrue( !StringUtils.isBlank( (String) jsonMap.get( "startDate" ) ) , I18nUtil.getI18nText("report.rate.startDate") );
        try {
            startDate = sdf.parse( (String) jsonMap.get( "startDate" ) );
        } catch (ParseException e) {
            e.printStackTrace();
        }
        /*if ( !StringUtils.isBlank( (String) jsonMap.get( "startDate" ) ) ){
            try {
                startDate = sdf.parse( (String) jsonMap.get( "startDate" ) );
            } catch (ParseException e) {
                e.printStackTrace();
            }

        }else {
            Date date=new Date();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DAY_OF_MONTH, -1);

            startDate = calendar.getTime();
        }*/

        if ( !StringUtils.isBlank( (String) jsonMap.get( "endDate" ) ) ){
            try {
                endDate = sdf.parse( (String) jsonMap.get( "endDate" ) );
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        List<Map<String,Object >> rtnlist = new ArrayList<>();

        List<Map<String,Object> > list = cpkReportMapper.findCPKFailCountByReport( site ,machineType,cncType,resrce,startDate,endDate );

        Assert.isTrue( list.size() >1 , I18nUtil.getI18nText("qc.point.dataISerror"));

        if ( StringUtils.isBlank( fail ) ){
            List<Map<String,Object >> parameterlist = dcGroupAdviceService.findDCParameterList( site , dcBo );

            if ( parameterlist.isEmpty() ){
                throw BusinessException.build("qc.point.dcGroupnotBlank",new String[]{dcBo});
            }

            for ( Map<String,Object> dcParameter : parameterlist ){
                Map<String,Object> rtnMap = new HashMap<>() ;
                rtnMap.put( "parameterName", dcParameter.get("PARAMETER_NAME") );
                rtnMap.put( "description" , dcParameter.get("DESCRIPTION") );
                BigDecimal minValueGap = (BigDecimal) dcParameter.get( "MIN_VALUE" );
                BigDecimal maxValueGap = (BigDecimal) dcParameter.get( "MAX_VALUE" );
                BigDecimal dcValueMask = new BigDecimal((String) dcParameter.get( "DC_VALUE_MASK" )); //标准值
                rtnMap.put( "nominal",dcValueMask );
                rtnMap.put( "max",maxValueGap );
                rtnMap.put( "min",minValueGap);
                String dbFieldName = (String) dcParameter.get( "PROMPT" );

                calculateCPK( list , rtnMap , dbFieldName  );

                rtnlist.add( rtnMap );

            }

        }else {
            Map<String,Object> rtnMap = new HashMap<>();
            Map<String,Object > dcParameter = cpkReportMapper.findFaiDataByname( dcGroup , fail );
            Assert.notNull( dcParameter ,I18nUtil.getI18nText("qc.point.failIsExsited",new String []{ fail ,dcBo }) );
            rtnMap.put( "parameterName", dcParameter.get("PARAMETER_NAME") );
            rtnMap.put( "description" , dcParameter.get("DESCRIPTION") );
            BigDecimal minValueGap = (BigDecimal) dcParameter.get( "MIN_VALUE" );
            BigDecimal maxValueGap = (BigDecimal) dcParameter.get( "MAX_VALUE" );
            BigDecimal dcValueMask = new BigDecimal((String) dcParameter.get( "DC_VALUE_MASK" )); //标准值
            rtnMap.put( "nominal",dcValueMask );
            rtnMap.put( "max",maxValueGap );
            rtnMap.put( "min",minValueGap);
            String dbFieldName = (String) dcParameter.get( "PROMPT" );

            calculateCPK( list , rtnMap , dbFieldName );

            rtnlist.add( rtnMap );

        }

        return rtnlist;
    }

    /**
     * 计算FAI CPK
     * @param list
     * @param rtnMap
     * @param dbFieldName
     */
    public void calculateCPK(  List<Map<String,Object> > list , Map<String,Object> rtnMap , String dbFieldName ){
        BigDecimal minValueGap = (BigDecimal)rtnMap.get("min");
        BigDecimal dcValueMask = (BigDecimal)rtnMap.get("nominal");
        BigDecimal maxValueGap =  (BigDecimal)rtnMap.get("max");

        /*计算cpk*/
        List<BigDecimal> bigDecimals = new ArrayList<>();
        for ( Map<String,Object> map : list  ){
            bigDecimals.add( (BigDecimal)map.get( dbFieldName ) );
        }
        BigDecimal sum = BigDecimal.ZERO;
        for ( int i =0;i<bigDecimals.size();i++ ){
            sum = sum.add( bigDecimals.get(i) );
        }
        BigDecimal num = new BigDecimal( bigDecimals.size() );
        BigDecimal mean = sum.divide( num, 3, RoundingMode.HALF_UP ); //取三位

        BigDecimal squareSum =  BigDecimal.ZERO;
        for ( int i =0;i<bigDecimals.size();i++ ){
            BigDecimal A = bigDecimals.get( i ).subtract( mean );

            squareSum = squareSum.add( A.multiply( A ) );
        }
        BigDecimal std = squareSum.divide( num ,8 , BigDecimal.ROUND_HALF_UP );
        Double stdDev1 = Math.sqrt( std.doubleValue() );  //开根号
        BigDecimal stddev = BigDecimal.valueOf( stdDev1 );  //标准差
        stddev.setScale( 3 , BigDecimal.ROUND_HALF_UP ); //取三位


        BigDecimal lsl = dcValueMask.add( minValueGap );
        BigDecimal usl = dcValueMask.add( maxValueGap );
        BigDecimal UL = maxValueGap.subtract( minValueGap );  //usl-lsl

        BigDecimal six = new BigDecimal("6");
        BigDecimal three = new BigDecimal( "3" );
        BigDecimal SS = six.multiply( stddev );  //6 * stdev
        BigDecimal TS = three.multiply( stddev ); //3*STDDEV
        BigDecimal UM = usl.subtract( mean ); //USL-MEAN
        BigDecimal ML =  mean.subtract( lsl ); //MEAN-LSL

        BigDecimal cp = UL.divide( SS , 3, BigDecimal.ROUND_HALF_UP ); // CP = ( USL - LSL )/( 6 * stdev )

        BigDecimal ucpk = UM.divide( TS ,3, BigDecimal.ROUND_HALF_UP );  //UCPK = (USL-MEAN)/(3*STDDEV)

        BigDecimal lcpk = ML.divide( TS ,3, BigDecimal.ROUND_HALF_UP); // LCPK = (MEAN-LSL)/（3*STDDEV）

        BigDecimal cpk = ucpk.min( lcpk ) ; //UCPK、LCPK最小值
       // cpk.setScale( 3, BigDecimal.ROUND_HALF_UP );

        rtnMap.put("cp",cp);
        rtnMap.put("ucpk",ucpk);
        rtnMap.put("lcpk",lcpk);
        rtnMap.put("cpk",cpk);
    }

}
